﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using VxlEditor.Common;
using System.Drawing.Drawing2D;

namespace VxlEditor.ColorChooser
{
    public partial class VxlColorChooser : UserControl
    {
        private Color selectedColor;
        private Color bwColor;
        private Color finalColor;
        private int alphaValue = 255;

        public Color Color
        {
            get { return finalColor; }
        }

        public VxlColorChooser()
        {
            InitializeComponent();
            selectedColor = Color.White;
            finalColor = Color.White;
            bwColor = Color.White;

            Bitmap bmp = new Bitmap(hueSelector.Width, hueSelector.Height);

            int deltaX = hueSelector.Width / 3;
            int deltaY = hueSelector.Height / 3;

            bool[,] colors = new bool[3,3];
            colors[0, 1] = true;
            colors[1, 0] = true;
            colors[1, 2] = true;
            colors[2, 1] = true;

            for (int i = 0; i < 3; i ++)
            {
                for (int j = 0; j < 3; j ++)
                {
                    for (int k = 0; k < deltaX; k++)
                    {
                        for (int l = 0; l < deltaY; l++)
                        {
                            if (colors[i, j])
                                bmp.SetPixel(i*deltaX + k, j*deltaY + l, Color.Black);
                            else
                                bmp.SetPixel(i * deltaX + k, j * deltaY + l, Color.Transparent);
                        }
                    }
                }
            }

            hueSelector.Image = bmp;

            SetupColorSlider();
            SetSolidColors();
        }

        private void SetSolidColors(){

            // set solid colors on the backgroundColorPanel, alphaSlider and selectedColorPanel
            CreateAlphaSlider();

            Bitmap colorWheelImage = new Bitmap(colorSelectorPanel.Width, colorSelectorPanel.Height);
            Graphics g = Graphics.FromImage(colorWheelImage);
            g.InterpolationMode = InterpolationMode.HighQualityBicubic;
            CreateColorWheel(g, Color.Black, 0, 0, colorSelectorPanel.Width, colorSelectorPanel.Height);
            colorSelectorPanel.BackgroundImage = colorWheelImage;
            
            finalColor = Color.FromArgb(alphaValue,
                selectedColor.R,
                selectedColor.G,
                selectedColor.B
                );

            selectedColorForeground.Image= CreateSolidBitmap(selectedColorForeground.Width, selectedColorForeground.Height);

            ForceRedraw(colorSelectorPanel);
            ForceRedraw(selectedColorForeground);
        }

        private void CreateAlphaSlider(){
            int width = alphaColorForeground.Width;
            int height = alphaColorForeground.Height;

            Bitmap img = new Bitmap(width, height);

            float delta =  (float)Math.Ceiling((255.0f / ((float)width*2.5f-10.0f)));
            for (int i = 0; i < 10; i++ )
                for (int j = 0; j < height; j++)
                {
                    int alpha = 0;
                    if(i < 5 )
                        alpha = 255;
                    img.SetPixel(i, j, Color.FromArgb(alpha, selectedColor.R, selectedColor.G, selectedColor.B));
                }

            for (int i = 5; i < width-5; i++ )
                for (int j = 0; j < height; j++)
                {
                    img.SetPixel(i, j, Color.FromArgb(Math.Min(255, Math.Max(255 - (int)delta * i, 0)), selectedColor.R, selectedColor.G, selectedColor.B));
                }
            
            alphaColorForeground.Image = img;

            ForceRedraw(alphaColorForeground);
        }

        private Bitmap CreateSolidBitmap(int width, int height){
            Bitmap solidBmp = new Bitmap(width, height);

            for (int i = 0; i < width; i++)
                for (int j = 0; j < height; j++)
                {
                    solidBmp.SetPixel(i, j, finalColor);
                }

            return solidBmp;
        }

        private void SetupColorSlider(){
            int width = this.bwColorSlider.Width;
            int height = this.bwColorSlider.Height;
            Bitmap img = new Bitmap(width, height);

            int delta =  (int)Math.Floor(255.0f / (float)width);
            int color = 255;

            for(int i = 0; i<width; i++){
                for(int j = 0; j<height; j++){
                    img.SetPixel(i, j, Color.FromArgb(255, color, color, color));
                }
                color -= delta;
            }

            this.bwColorSlider.BackgroundImage = img;
        }

        private Color ConvertPointToColor(MouseEventArgs e, object obj)
        {
            if (obj is Panel)
            {
                return ((Bitmap)((Panel)obj).BackgroundImage).GetPixel(e.X, e.Y);
            }
            if (obj is TransparentControl)
            {
                return ((Bitmap)((TransparentControl)obj).Image).GetPixel(e.X, e.Y);
            }
            return Color.Transparent;
        }

        private void colorSlider_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button.HasFlag(MouseButtons.Left))
            {
                if (e.X < 0 || e.Y < 0 || e.X >= bwColorSlider.Size.Width || e.Y >= bwColorSlider.Size.Height)
                    return;

                Color pixelColor = ConvertPointToColor(e, sender);

                selectedColor= Color.FromArgb(alphaValue, pixelColor.R, pixelColor.G, pixelColor.B);
                SetSolidColors();
            }
        }

        private void alphaColorForeground_MouseClick(object sender, MouseEventArgs e)
        {
            Color pixelColor = ConvertPointToColor(e, sender);

            alphaValue = pixelColor.A;

            SetSolidColors();
            ForceRedraw(selectedColorForeground);
        }

        private void alphaColorForeground_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button.HasFlag(MouseButtons.Left))
            {
                if (e.X < 0 || e.Y < 0 || e.X >= alphaColorForeground.Size.Width || e.Y >= alphaColorForeground.Size.Height)
                    return;

                Color pixelColor = ConvertPointToColor(e, sender);

                alphaValue = pixelColor.A;

                SetSolidColors();

                ForceRedraw(selectedColorForeground);
            }
        }

        private void ForceRedraw(object sender){
            if(sender is Panel){
                ((Panel)sender).Invalidate();
                ((Panel)sender).Update();
            }
            else if (sender is TransparentControl)
            {
                ((TransparentControl)sender).Invalidate();
                ((TransparentControl)sender).Update();
            }
        }

        // Draw a color wheel in the indicated area.
        private void CreateColorWheel(Graphics gr, Color outline_color, int xmin, int ymin, int wid, int hgt)
        {
            Rectangle rect = new Rectangle(xmin, ymin, wid, hgt);
            GraphicsPath wheel_path = new GraphicsPath();
            wheel_path.AddEllipse(rect);
            wheel_path.Flatten();

            int num_pts = (wheel_path.PointCount - 1) / 3;
            Color[] surround_colors = new Color[wheel_path.PointCount];
            float r = 255, g = 0, b = 0;
            float dr, dg, db;
            dr = -255 / num_pts;
            db = 255 / num_pts;
            for (int i = 0; i < num_pts; i++)
            {
                surround_colors[i] = Color.FromArgb(255, (int)r, (int)g, (int)b);
                r += dr;
                b += db;
            }

            r = 0; g = 0; b = 255;
            dg = 255 / num_pts;
            db = -255 / num_pts;
            for (int i = num_pts; i < 2 * num_pts; i++)
            {
                surround_colors[i] = Color.FromArgb(255, (int)r, (int)g, (int)b);
                g += dg;
                b += db;
            }

            r = 0; g = 255; b = 0;
            dr = 255 / (wheel_path.PointCount - 2 * num_pts);
            dg = -255 / (wheel_path.PointCount - 2 * num_pts);
            for (int i = 2 * num_pts; i < wheel_path.PointCount; i++)
            {
                surround_colors[i] = Color.FromArgb(255, (int)r, (int)g, (int)b);
                r += dr;
                g += dg;
            }

            using (PathGradientBrush path_brush = new PathGradientBrush(wheel_path))
            {
                path_brush.CenterColor = bwColor;
                path_brush.SurroundColors = surround_colors;

                gr.FillPath(path_brush, wheel_path);

                // It looks better if we outline the wheel.
                using (Pen thick_pen = new Pen(outline_color, 2))
                {
                    gr.DrawPath(thick_pen, wheel_path);
                }
            }
        }

        private void colorSelectorPanel_MouseClick(object sender, MouseEventArgs e)
        {
            this.hueSelector.Location = new Point(e.Location.X - this.hueSelector.Size.Width / 2, e.Location.Y - this.hueSelector.Size.Height/ 2);
            selectedColor = ConvertPointToColor(e, sender);

            SetSolidColors();
            //this.selectedColorForeground.Image = CreateSolidBitmap(selectedColorForeground.Width, selectedColorForeground.Height);            

        }

        private void bwColorSlider_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.X < 0 || e.Y < 0 || e.X >= bwColorSlider.Size.Width || e.Y >= bwColorSlider.Size.Height)
                return;

            Color pixelColor = ConvertPointToColor(e, sender);

            bwColor = Color.FromArgb(alphaValue, pixelColor.R, pixelColor.G, pixelColor.B);

            SetSolidColors();
        }
    }
}

